package cc.admin.common.db.table.base;

import cc.admin.common.db.table.entity.DbEntity;
import cc.admin.common.db.table.entity.DbSql;
import cc.admin.common.db.table.writer.MysqlWriter;
import cc.admin.common.db.table.writer.OracleWriter;
import cc.admin.common.db.table.writer.SqlServerWriter;
import cc.admin.common.db.util.DbConstants;
import cc.admin.common.db.util.FreemarkerUtil;
import cc.admin.common.db.util.TypeConvertUtil;
import cc.admin.common.util.dynamic.db.DynamicDBUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;
import java.util.Map;
import java.util.Set;
/**
 * @author: ZhangHouYing
 * @date: 2018-06-24
 */
@Slf4j
@Data
public abstract class EtlWriter extends BaseEtl {

	protected String dbType;
	protected JdbcTemplate jdbcTemplate;

	public static EtlWriter getInstance(JdbcTemplate jdbcTemplate) {
		String databaseProductName = getDatabaseProductName(jdbcTemplate);
		EtlWriter etlWriter = null;
		switch (databaseProductName) {
			case DbConstants.DB_NAME_MYSQL:
				etlWriter = new MysqlWriter();
				break;
			case DbConstants.DB_NAME_ORACLE:
				etlWriter = new OracleWriter();
				break;
			case DbConstants.DB_NAME_SQLSERVER:
				etlWriter = new SqlServerWriter();
				break;
			default: //可选
				throw new RuntimeException("不能识别的etlWriter:" + databaseProductName);
		}
		etlWriter.setJdbcTemplate(jdbcTemplate);
		etlWriter.setDbType(databaseProductName);
		return etlWriter;
	}

	/**
	 * 根据dbKey初始化
	 *
	 * @param dbKey
	 * @return
	 */
	public static EtlWriter getInstance(String dbKey, Boolean safeModel) {
		return getInstance(DynamicDBUtil.getJdbcTemplate(dbKey, safeModel));
	}

	/**
	 * 写建表语句
	 *
	 * @param dbEntity 表结构
	 * @return
	 */
	public abstract String writerSql(DbEntity dbEntity);

	/**
	 * 删除表语句
	 *
	 * @param tableName
	 * @return
	 */
	public static String dropSql(String tableName) {
		return String.format("drop table %s", tableName);
	}

	public void addTool(Map<String, Object> map) {
		map.put("columnConvert", null);
	}

	protected String renderCreateTableSql(String template, DbEntity dbEntity) {
		Map<String, Object> map = Maps.newHashMap();
		map.put("typeConvertUtil", new TypeConvertUtil());
		map.put("entity", dbEntity);
		map.put("columnList", dbEntity.getDbColumnList());
		map.put("pkList", dbEntity.getPkList());
		addTool(map);
		String createTableSql = FreemarkerUtil.renderContent(template, map);
		return createTableSql;
	}

	/**
	 * 这里考虑要获取原始表数据类型
	 *
	 * @param distTable
	 * @param sourceDataList
	 * @param autoMerge
	 * @param uniqueColumns
	 */
	public void writerData(String distTable, List<Map<String, Object>> sourceDataList, String autoMerge, String uniqueColumns) {
		//目前只支持单列作为唯一列
		for (Map<String, Object> sourceData : sourceDataList) {
			// 增量更新必须指定唯一字段
			if ("1".equals(autoMerge) && StrUtil.isNotEmpty(uniqueColumns)) {
				DbSql sql = getDeleteSql(uniqueColumns, distTable, sourceData);
				Object[] valueArray = sql.getParamArray();
				jdbcTemplate.update(sql.getSql(), valueArray);
			}
			DbSql sql = getDbSql(distTable, sourceData);
			Object[] valueArray = sql.getParamArray();
			if (log.isDebugEnabled()) {
				log.info("sql:{}", sql.getSql());
				for (int i = 0; i < valueArray.length; i++) {
					log.info("param[{}]:{}", i, valueArray[i]);
				}
			}
			jdbcTemplate.update(sql.getSql(), valueArray);
		}
	}

	private DbSql getDeleteSql(String uniqueColumns, String distTable, Map<String, Object> dataMap) {
		DbSql dbSql = new DbSql();
		List<Object> paramList = Lists.newArrayList();
		StringBuilder sb = new StringBuilder();
		sb.append("delete from ").append(distTable).append(" where ");
		String[] uniqueColumnList = StrUtil.split(uniqueColumns, ",");
		for (String uniqueColumn : uniqueColumnList) {
			sb.append(uniqueColumn).append("=? ,");
			paramList.add(getParamValue(uniqueColumn, dataMap));
		}
		sb = sb.deleteCharAt(sb.length() - 1);
		dbSql.setSql(sb.toString());
		dbSql.setParams(paramList);
		return dbSql;
	}

	protected DbSql getDbSql(String tableName, Map<String, Object> dataMap) {
		DbSql dbSql = new DbSql();
		List<Object> paramList = Lists.newArrayList();
		StringBuilder sb = new StringBuilder();
		sb.append("insert into ").append(tableName).append("(");
		Set<String> keySet = dataMap.keySet();
		for (String key : keySet) {
			if (DbConstants.DB_ROW_NUM.equalsIgnoreCase(key)) {
				continue;
			}
			sb.append(key).append(",");
		}
		sb = sb.deleteCharAt(sb.length() - 1);
		sb.append(") values(");
		for (String key : keySet) {
			if (DbConstants.DB_ROW_NUM.equalsIgnoreCase(key)) {
				continue;
			}
			sb.append("?,");
			paramList.add(getParamValue(key, dataMap));
		}
		sb = sb.deleteCharAt(sb.length() - 1);
		sb.append(")");
		dbSql.setSql(sb.toString());
		dbSql.setParams(paramList);
		return dbSql;
	}

	protected Object getParamValue(String key, Map<String, Object> dataMap) {
		Object value = dataMap.get(key);
		return value;
	}

}
